const WebSocket = require('ws')
const config = require('config')
const jwt = require('jsonwebtoken')
const trash = require('@/utils/ini.unit')
const { getLocationParams } = require('@/utils/common.util')
const { receiveMessage, sendMessage, authenticationFail } = require('./chat')
const chalk = require('chalk')

const clients = {}
const server = new WebSocket.Server({
  port: config.get('ws.port'),
  path: '/socket/message'
})

server.on('connection', async (client, req) => {
  const id = getLocationParams(req.url, 'id') // 用户userId
  const token = getLocationParams(req.url, 'token') // 用户登录认证token
  const authId = getLocationParams(req.url, 'authId') // 微信扫码登录websocket连接

  // 如果存在authId则直接认证成功（微信登录扫码socket唯一标识）
  if (authId) {
    client.clientUniqueId = authId
    clients[authId] = [client]
    sendMessage('连接建立成功', client)
  } else {
    if (!id || !token) return authenticationFail(client)
    try {
      const decodedToken = jwt.verify(token, trash.jsonSecretkey)
      if (decodedToken.id !== id) return authenticationFail(client)
    } catch (error) {
      return authenticationFail(client)
    }
    client.clientUniqueId = id
    if (!clients[id]?.length) {
      clients[id] = [client]
    } else {
      clients[id].push(client)
    }
    sendMessage('连接建立成功', client)
  }

  client.on('message', async data => {
    const accept = data.toString()
    if (accept === 'ping') {
      sendMessage('pong', client)
    } else {
      const messageJson = JSON.parse(accept)
      const messageInfo = await receiveMessage(messageJson)
      // 信息发送成功后将消息推送给被发送人
      if (messageInfo.sendSuccessFlag) {
        const toId = messageInfo.toId
        // 把消息推送给接收人
        for (let i = 0; i < clients[toId]?.length; i++) {
          sendMessage({ ...messageInfo, im: true }, clients[toId][i])
        }
      }
      // 消息发送结果推送给发送人
      sendMessage({ ...messageInfo, sendResultcallback: true, im: true }, client)
    }
  })

  client.on('close', error => {
    console.error(chalk.red('客户端主动断开连接' + '：' + error))
    const clientUniqueId = client.clientUniqueId
    for (let i = 0; i < clients[clientUniqueId]?.length; i++) {
      if (clients[clientUniqueId][i] === client) {
        clients[clientUniqueId].splice(i, 1)
        if (clients[clientUniqueId].length === 0) {
          delete clients[clientUniqueId]
        }
        break
      }
    }
    client.close()
  })
})

module.exports = clients
